<?php
namespace App\Libraries\NoSql;

/**
 * Redis 客户端
 * @package App\Libraries\NoSql
 */
class RedisClient {

	#region 属性

	/**
	 * redis 配置
	 */
	private $config;

	/**
	 * redis 对象
	 * @var \Redis
	 */
	private $redis;

	/**
	 * 是否启用
	 * @var boolean
	 */
	private $enable;

	#endregion

	#region 构造函数

	/**
	 * 构造函数
	 * @param $config 相关配置
	 */
	public function __construct($config) {
		$this->config = $config;
		if (!extension_loaded('redis')) {
			throw_exception('加载Redis失败，检查Redis扩展是否添加');
		}
	}

	#endregion

	#region Redis 字符串(String)

	/**
	 * 得到某个key的值（string值）
	 * @param $key 键
	 * @return bool
	 */
	public function get($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->get($this->_setKeyPrefix($key));
	}

	/**
	 * 写入key 和 value（string值）
	 * @param $key 键
	 * @param $value 值
	 * @param $expire 有效时间
	 * @return bool
	 */
	public function set($key, $value, $expire = CACHE_EXPIRE) {
		$this->_init();
		if (!$this->enable) return false;
		if (is_int($expire)) {
			$result = $this->redis->setex($this->_setKeyPrefix($key), $expire, $value);
		} else {
			$result = $this->redis->set($this->_setKeyPrefix($key), $value);
		}
		return $result;
	}

	/**
	 * 移除给定的一个或多个key。
	 * @param $key 键
	 * @return bool
	 */
	public function rm($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->delete($this->_setKeyPrefix($key));
	}

	/**
	 * 清空
	 * @return bool
	 */
	public function clear() {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->flushDB();
	}

	#endregion

	#region Redis Hash相关

	/**
	 * 将哈希表 key 中的字段 field 的值设为 value 。
	 * @param $key 键
	 * @param $field 域
	 * @param $value 值
	 * @return bool
	 */
	public function hSet($key, $field, $value) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hSet($this->_setKeyPrefix($key), $field, $value);
	}

	/**
	 * 获取存储在哈希表中指定字段的值
	 * @param $key 键
	 * @param $field
	 * @return $value
	 */
	public function hGet($key, $field) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hGet($this->_setKeyPrefix($key), $field);
	}

	/**
	 * 获取在哈希表中指定 key 中所有域
	 * @param $key 键
	 * @return array
	 */
	public function hKeys($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hKeys($this->_setKeyPrefix($key));
	}

	/**
	 * 获取在哈希表中指定 key 中所有值
	 * @param $key 键
	 * @return array
	 */
	public function hVals($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hVals($this->_setKeyPrefix($key));
	}

	/**
	 * 获取在哈希表中指定 key 中所有域和值
	 * @param $key 键
	 * @return array
	 */
	public function hGetAll($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hGetAll($this->_setKeyPrefix($key));
	}

	/**
	 * 判断哈希表中指定 key 中是否存在域
	 * @param $key 键
	 * @return bool
	 */
	public function hExists($key, $field) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hExists($this->_setKeyPrefix($key), $field);
	}

	/**
	 * 删除哈希表中指定 key 和field的值
	 * @param $key 键
	 * @return bool
	 */
	public function hDel($key, $field1, $field2 = null, $field3 = null) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hDel($this->_setKeyPrefix($key), $field1, $field2, $field3);
	}

	/**
	 * 删除哈希表中指定 key 的值
	 * @param $key 键
	 * @return bool
	 */
	public function hDelAll($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->delete($this->_setKeyPrefix($key));
	}

	/**
	 * 在哈希表中为指定的域增加值
	 * @param $key 键
	 * @param $field 域
	 * @param $value 增加的值
	 * @return bool
	 */
	public function hIncrBy($key, $field, $value) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->hIncrBy($this->_setKeyPrefix($key), $field, $value);
	}

	#endregion

	#region Redis Set相关

	/**
	 * 向集合添加一个成员
	 * @param $key 键
	 * @param $value 值
	 * @return bool
	 */
	public function sAdd($key, $value) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->sAdd($this->_setKeyPrefix($key), $value);
	}

	/**
	 * 返回集合中元素的数量
	 * @param $key
	 * @return mixed
	 */
	public function sCard($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->sCard($this->_setKeyPrefix($key));
	}

	/**
	 * 判断元素是否是集合 key 的成员
	 * @param $key 键
	 * @param $value 值
	 * @return bool
	 */
	public function sIsMember($key, $value) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->sIsMember($this->_setKeyPrefix($key), $value);
	}

	/**
	 * 返回集合中的所有成员
	 * @param $key
	 * @return boolean
	 */
	public function sMembers($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->sMembers($this->_setKeyPrefix($key));
	}

	/**
	 * 向集合添加一个成员
	 * @param $key 键
	 * @param $value 值
	 * @return bool
	 */
	public function sRem($key, $value) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->sRem($this->_setKeyPrefix($key), $value);
	}

	/**
	 * 删除集合中指定 key 的值
	 * @param $key 键
	 * @return mixed
	 */
	public function sDelAll($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->delete($this->_setKeyPrefix($key));
	}

	#endregion

	#region Redis List 相关

	/**
	 * 将一个或多个值 value 插入到列表 key 的表头
	 * @param $key 关键字
	 * @param $value 要插入的值
	 * @return int
	 */
	public function lPush($key, $value) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->lPush($this->_setKeyPrefix($key), $value);
	}

	/**
	 * 移除并获取列表最后一个元素
	 * @param $key
	 * @return  string if command executed successfully BOOL FALSE in case of failure (empty list)
	 */
	public function rPop($key) {
		$this->_init();
		if (!$this->enable) return false;
		return $this->redis->rPop($this->_setKeyPrefix($key));
	}

	#endregion

	#region 私有方法

	/**
	 * 初始化
	 */
	private function _init() {
		static $redis;
		if (!isset($redis) || !$redis) {
			$func = $this->config->pconnect ? 'pconnect' : 'connect';
			$redis = new \Redis();
			$this->enable = $redis->$func($this->config->host, $this->config->port);
			if ($this->enable && isset($this->config->password) && $this->config->password) {
				$this->enable = $redis->auth($this->config->password);
			}
			$redis->select($this->config->db);
		}
		$this->redis = $redis;
	}

	/**
	 * 设置Key的前缀
	 * @param $key
	 * @return string
	 */
	private function _setKeyPrefix($key) {
		if (isset($this->config->prefix) && $this->config->prefix) {
			return "{$this->config->prefix}_{$key}";
		}
		return $key;
	}
	#endregion
}